import axios, {
  InternalAxiosRequestConfig,
  AxiosResponse,
  CancelTokenSource,
  AxiosError,
} from "axios";
import { ElLoading } from "element-plus";
//全局消息提示
import message from "./message";

interface RequestConfig extends InternalAxiosRequestConfig {
  url: string; //接口地址
  method?: "get" | "post"; //default post
  params?: any;
  data?: any;
  showLoading?: boolean;
  showError?: boolean;
  allowRepeat?: boolean;
  errorCallback?: (data: any) => void; // 错误处理
}

//重复请求管理,存储pending状态请求
const pendingRequests = new Map<string, CancelTokenSource>();

const instance = axios.create({
  // withCredentials: true, //跨域携带token
  baseURL: "",
  timeout: 30 * 1000,
  headers: {},
});

/**
 * 生成唯一标识
 * @param config axios请求配置
 */
const generateRequestKey = (config: RequestConfig): string => {
  const { method, url, params, data } = config;
  return [
    method?.toUpperCase(),
    url,
    JSON.stringify(params || {}),
    JSON.stringify(data || {}),
  ].join(":");
};

//loading 管理
let loadingInstance: ReturnType<typeof ElLoading.service> | null = null;
let loadingCount = 0; // 记录loading数量

const showLoading = (config: RequestConfig) => {
  if (config.showLoading) {
    loadingCount++;
    if (loadingCount === 1) {
      loadingInstance = ElLoading.service({
        lock: true,
        text: "加载中...",
        background: "rgba(0,0,0,0.7)",
        fullscreen: true,
      });
    }
  }
};
const hideLoading = (config: RequestConfig) => {
  if (config.showLoading && loadingInstance) {
    loadingCount--;
    if (loadingCount === 0) {
      loadingInstance.close();
      loadingInstance = null;
    }
  }
};

//请求拦截
instance.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    //as类型断言将原生配置转换为自定义
    const reqConfig = config as RequestConfig;
    //重复请求拦截
    const requestKey = generateRequestKey(reqConfig);
    if (!reqConfig.allowRepeat) {
      if (pendingRequests.has(requestKey)) {
        pendingRequests.get(requestKey)?.cancel("重复请求已拦截");
      }
      const source = axios.CancelToken.source();
      reqConfig.cancelToken = source.token;
      pendingRequests.set(requestKey, source);
    }

    //loading
    if (reqConfig.showLoading !== false) {
      showLoading(reqConfig);
    }
    return reqConfig;
  },
  (error: AxiosError) => {
    const config = error.config as RequestConfig;
    if (config && config.showLoading !== false) {
      hideLoading(config);
    }
    message.error("请求发送失败");
    return Promise.reject(error);
  }
);
//响应拦截
instance.interceptors.response.use(
  (response: AxiosResponse) => {
    const config = response.config as RequestConfig;
    //移除重复请求
    const requestKey = generateRequestKey(config);
    pendingRequests.delete(requestKey);
    if (config.showLoading !== false) {
      hideLoading(config);
    }
    const { code, msg } = response.data;
    if (code === 1 || response.status == 200) {
      const contentType = response.headers["content-type"];
      if (
        contentType == "text/html;charset=UTF-8" ||
        contentType == "application/pdf" ||
        contentType == "image/png"
      ) {
        return response;
      } else {
        return response.data;
      }
    } else {
      if (config.errorCallback) {
        config.errorCallback(response.data);
      }
      return Promise.reject({
        showError: config.showError,
        msg: msg || "请求失败",
      });
    }
  },
  (error: AxiosError) => {
    if (error.config) {
      const config = error.config as RequestConfig;
      const requestKey = generateRequestKey(config);
      pendingRequests.delete(requestKey);

      if (config.showLoading !== false) {
        hideLoading(config);
      }
    }
    if (axios.isCancel(error)) {
      console.warn("已拦截重复请求", error.message);
      return Promise.reject({ showError: false, msg: error.message });
    }

    //网络错误
    return Promise.reject({
      showError: true,
      msg: "网络异常，请检查网络连接",
    });
  }
);

/**
 * 发送请求
 * @param config 请求配置
 */
const request = (config: Omit<RequestConfig, "url"> & { url: string }) => {
  try {
    const defaultConfig: Partial<RequestConfig> = {
      method: "get",
      showLoading: true,
      showError: true,
      allowRepeat: false,
    };
    const finalConfig: RequestConfig = { ...defaultConfig, ...config };
    return instance(finalConfig);
  } catch (error: any) {
    if (error.showError) {
      message.error(error.msg || "请求处理失败");
    }
    return null;
  }
};

export default request;
